#include "cmd_user_session.h"
#include "cmd_view.h"

#include <boost/algorithm/string/erase.hpp>

using namespace vpm::cmo;

CmdUserSession::CmdUserSession(CmdViewPtr & view):m_cmdView(view)
{
	m_bLogin = false; 

	m_bStart = true; 	
	m_bCmdFinished = false; 
	m_seekNode = m_cmdView->m_rootNode;
}


void CmdUserSession::rewind()
{
	m_seekNode = m_cmdView->m_rootNode;
	m_validInput.str("");
	m_bCmdFinished = false; 
}

void CmdUserSession::tab_action()
{
	std::string cmd(m_inputWord.begin(),m_inputWord.end());

	if (!cmd.empty())
	{			
		m_inputWord.clear(); 
	}

	CmdNodes matched = m_seekNode->get_matched_nodes(cmd);
	if (matched.size()  == 1 )
	{
		m_seekNode = *matched.begin();
		if (m_seekNode->nodeType == CmdNode::NamedValue)
		{
			outln(); 
			std::string tmpStr =std::string("input value for ")+ m_seekNode->nodeName +"\n";
			m_stringWriter(tmpStr.c_str());
			std::string inWord(m_inputWord.begin(),m_inputWord.end());
			m_stringWriter(inWord.c_str());
		}
		else 
		{
			std::string leftStr = m_seekNode->nodeName; 
			boost::erase_head(leftStr,(int)cmd.length());
			m_stringWriter(leftStr.c_str());
		}
	}
	else if (matched.size() > 1) 
	{
		const std::string & hint =m_seekNode->prompt_children((int)4);
		if ( !hint.empty())
		{
			outln();
			m_stringWriter( hint.c_str());	
		}
	}
	else 
	{ 
		//no matched nodes. 
		//do nothing 
	}

}

void CmdUserSession::nonspace_action(char ch)
{
	m_inputWord.push_back(ch);
	m_charWriter(ch);
	if (m_bStart)
	{
		m_seekNode = m_cmdView->m_rootNode;
		m_bStart = false; 
	}
}

bool CmdUserSession::space_action()
{		
	std::string cmd(m_inputWord.begin(),m_inputWord.end());
	if (!cmd.empty())
	{					
		m_inputWord.clear();
	}

	size_t indent = 4; 
	CmdNodes matched = m_seekNode->get_matched_nodes(cmd);
	if (!matched.empty())
	{		
		m_seekNode = *matched.begin();			

		indent += m_validInput.str().length() + m_seekNode->nodeName.length() ;

		const std::string & hint = m_seekNode->prompt_children((int)indent);
		if ( !hint.empty())
		{
			outln();
			m_stringWriter( hint.c_str());	
		}

		if (m_seekNode->nodeType == CmdNode::NamedValue)
		{
			m_validInput << cmd ;
			m_seekNode->nodeValue = cmd; 
		}
		else 
		{
			m_validInput << m_seekNode->nodeName ;			
		}

		if (m_seekNode->children.empty() && !cmd.empty())
		{
			m_validInput<<". ";
			m_bCmdFinished = true; 
		}		
		else 
		{
			m_validInput<<" ";
		}
		outln();
		m_stringWriter( m_validInput.str().c_str()) ; 		
	}			
	else 
	{		
		if (!m_validInput.str().empty()&& cmd.empty())
		{
			m_stringWriter(" ");
			return false;
		}

		if (!m_seekNode->children.empty())
		{
			outln();
			std::stringstream tmpStream;
			tmpStream<<  m_seekNode->prompt_children((int)m_validInput.str().length()) <<"." ;		
			m_stringWriter(tmpStream.str().c_str());
			outln();
		}		
	}			
	return  true; 
}	

void CmdUserSession::control_action(char ch)
{
	//should wait for enter key to execute the command.
	//std::cout <<"\n execute command \n";
	//command finished 
	if (ch == 0x08 || ch == 0x7f)
	{
		if (!m_inputWord.empty())
		{
			m_stringWriter("\b \b");
			m_inputWord.pop_back();			
		}
		else 
		{
			m_stringWriter("\a");//alarm 
		}
		long pos = m_validInput.tellp();
		if (pos > 0)
		{
			m_validInput.seekp(pos -1);
		}	
	}
	else 
	{
		if (!m_bCmdFinished)
		{		
			if (!m_inputWord.empty() )
			{
				this->space_action();
				if (!m_bCmdFinished)
				{
					outln();
					m_stringWriter("no such command");				
				}
			}else if (!m_validInput.str().empty())
			{
				outln();
				m_stringWriter("command not finished.");				
			}

			this->rewind();
		}		

		if (m_bCmdFinished)
		{	
			if (m_seekNode->executor)
			{
				CmdNodePtr pNode = m_seekNode;
				CmdExecutorPtr & pExecutor = m_seekNode->executor;
				pExecutor->command(pNode->command);
				while (pNode)
				{
					if (pNode->nodeType == CmdNode::Root)
					{
						break; 
					}
					else if (pNode->nodeType == CmdNode::NamedValue)
					{
						pExecutor->set_cmdword(pNode->index-1,pNode->nodeValue);
					}
					else 
					{
						pExecutor->set_cmdword(pNode->index-1,pNode->nodeName);
					}
					pNode = pNode->nodeParent;
				}
				//execute the command  
				(*m_seekNode->executor)(m_seekNode->command);

				//m_cmdHistory.add_command(m_validInput.str());
			}			
			outln();
			this->rewind();
		}
	}
}

void CmdUserSession::enter_action()
{


}
//parse phrase 
